#
#  Copyright 2008 Garth Williams
#
#  This file is part of CommandPost.
#
#  CommandPost is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  CommandPost is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with CommandPost.  If not, see <http://www.gnu.org/licenses/>.
#

require 'digest/sha1'
class User < ActiveRecord::Base
#  has_many :roles, :through => :responsibilities, :conditions => 'responsibilities.deleted_at IS NULL', :order => 'name'
#  has_many :responsibilities, :dependent => :destroy
  has_many :logs, :foreign_key => 'created_by_user_id'
  has_many :reports, :class_name => 'Report', :finder_sql =>
   'SELECT DISTINCT filtered_reports.*
    FROM
      (
        SELECT *
        FROM reports
        WHERE assigned_to_user_id = #{id}
        UNION
        SELECT reports.*
        FROM roles_users, roles, stage_assignments, stages, reports
        WHERE
          roles_users.deleted_at IS NULL
          AND
          roles.deleted_at IS NULL
          AND
          stage_assignments.deleted_at IS NULL
          AND
          stages.deleted_at IS NULL
          AND
          reports.deleted_at IS NULL
          AND
          reports.closed = 0
          AND
          roles.id = roles_users.role_id
          AND
          roles.id = stage_assignments.role_id
          AND
          stages.id = stage_assignments.stage_id
          AND
          stages.id = reports.stage_id
          AND
          roles_users.user_id = #{id}
      ) AS filtered_reports
    ORDER BY updated_at DESC'
  has_many :report_types, :class_name => 'ReportType', :finder_sql =>
   'SELECT DISTINCT report_types.*
    FROM roles_users, roles, report_type_permissions, report_types
    WHERE
      roles_users.deleted_at IS NULL
      AND
      roles.deleted_at IS NULL
      AND
      report_type_permissions.deleted_at IS NULL
      AND
      report_types.deleted_at IS NULL
      AND
      roles.id = roles_users.role_id
      AND
      roles.id = report_type_permissions.role_id
      AND
      report_types.id = report_type_permissions.report_type_id
      AND
      roles_users.user_id = #{id}
    ORDER BY report_types.name'
  
  acts_as_paranoid_versioned
  
  
  # ---------------------------------------
  # The following code has been generated by role_requirement.
  # You may wish to modify it to suit your need
  has_and_belongs_to_many :roles
  
#  attr_protected :roles

  
  # has_role? simply needs to return true or false whether a user has a role or not.  
  # It may be a good idea to have "admin" roles return true always
  def has_role?(role_in_question)
    @_list ||= self.roles.collect(&:name)
    return true if @_list.include?("admin")
    (@_list.include?(role_in_question.to_s) )
  end
  # ---------------------------------------
  
  
  
  
  # Virtual attribute for the unencrypted password
  attr_accessor :password

  validates_presence_of     :login, :email, :name
  validates_presence_of     :password,                   :if => :password_required?
  validates_presence_of     :password_confirmation,      :if => :password_required?
  validates_length_of       :password, :within => 4..40, :if => :password_required?
  validates_confirmation_of :password,                   :if => :password_required?
  validates_length_of       :login,    :within => 3..40
  validates_length_of       :email,    :within => 3..100
  validates_uniqueness_of   :login, :email, :case_sensitive => false
  before_save :encrypt_password
  after_save :add_log
  
  # prevents a user from submitting a crafted form that bypasses activation
  # anything else you want your user to change should be added here.
  attr_accessible :login, :email, :password, :password_confirmation, :name

  # Authenticates a user by their login name and unencrypted password.  Returns the user or nil.
  def self.authenticate(login, password)
    u = find_by_login(login) # need to get the salt
    u && u.authenticated?(password) ? u : nil
  end

  # Encrypts some data with the salt.
  def self.encrypt(password, salt)
    Digest::SHA1.hexdigest("--#{salt}--#{password}--")
  end

  # Encrypts the password with the user salt
  def encrypt(password)
    self.class.encrypt(password, salt)
  end

  def authenticated?(password)
    crypted_password == encrypt(password)
  end

  def remember_token?
    remember_token_expires_at && Time.now.utc < remember_token_expires_at 
  end

  # These create and unset the fields required for remembering users between browser closes
  def remember_me
    remember_me_for 2.weeks
  end

  def remember_me_for(time)
    remember_me_until time.from_now.utc
  end

  def remember_me_until(time)
    self.remember_token_expires_at = time
    self.remember_token            = encrypt("#{email}--#{remember_token_expires_at}")
    save(false)
  end

  def forget_me
    self.remember_token_expires_at = nil
    self.remember_token            = nil
    save(false)
  end

  # Returns true if the user has just been activated.
  def recently_activated?
    @activated
  end

  protected
    # before filter 
    def encrypt_password
      return if password.blank?
      self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
      self.crypted_password = encrypt(password)
    end
      
    def password_required?
      crypted_password.blank? || !password.blank?
    end
    
    def add_log
      if self.version == 1
        Log.new(:summary => "#{self.name} joined",
          :description => "Welcome to CommandPost #{self.name}", :created_by => self,
          :subject_action => 'c', :subject_type => 'user', :subject_id => self.id,
          :subject_version => self.version).save!
      end
    end
end
